#ifndef _THREAD_
#define  _THREAD_
#include<iostream>
#include<functional>
#include<memory>
#include<future>
#include<mutex>
#include<condition_variable>
#include<vector>
#include<queue>
#include<thread>
class threadpool
{
public:
    using ptr = std::shared_ptr<threadpool>;
    using Functor = std::function<void(void)>;
    //创建线程放入线程池
    threadpool(int thr_count=1):_stop(false)
    {
        for(int i=0;i<thr_count;i++)
        {
            _threads.emplace_back(&threadpool::entry,this);
        }
    }
    //析构
    ~threadpool(){stop();}
    void stop()
    {
        if(_stop==true) return;
        _stop=true;
        _cv.notify_all();
        for(auto& thread:_threads)
        {
           thread.join();
        }
    }
    
    template<typename F,typename...Args>
    auto push(F&&func,Args&&...args)->std::future<decltype(func(args...))>
    {

        //1.将传入的函数封装成一个packaged_task任务
        using return_type=decltype(func(args...));
        auto tmp_func=std::bind(std::forward<F>(func),std::forward<Args>(args)...);
        auto task=std::make_shared<std::packaged_task<return_type()>>(tmp_func);
        std::future<return_type> fu=task->get_future();
        //2.构造一个lambal匿名函数（捕获任务对象），函数内执行任务对象
        {
          std::unique_lock<std::mutex> lock(_mutex);
          //3.将构造出来的匿名函数对象，抛入到任务池中
          _taskpool.push_back([task](){(*task)();});
          _cv.notify_one();
        }
        return fu;
    }
    
    private:
    //线程池入口----循环从任务池中取任务
    void entry(){
        while(!_stop)
        {
        std::vector<Functor> tmp_taskpool;//局部变量
        {
     //加锁
     std::unique_lock<std::mutex> lock(_mutex);
     //等待任务池不为空，_stop被置为返回
     _cv.wait(lock,[this](){return _stop||!_taskpool.empty();});
     //取出任务进行执行
     tmp_taskpool.swap(_taskpool);
        }
      for(auto &task:tmp_taskpool)
      {
         task();
      }
    }
    }

private:
        std::atomic<bool> _stop;//控制线程的结束
        std::vector<Functor> _taskpool;//任务池
        std::mutex _mutex;
        std::condition_variable _cv;
        std::vector<std::thread> _threads;

};
#endif